from django.core.exceptions import ValidationError
from django.db import transaction
from django.db.models import F
from django.utils import timezone
from rest_framework import serializers

from BYD_ERP.utils.cont import NumberPrefix
from BYD_ERP.utils.generate_code import generate_code
from BYD_ERP.utils.get_inventory import get_inventory_by_goods
from goods_info.models import GoodsModel, GoodsInventoryModel
from basic_info.models import WarehouseModel
from warehouse_info.models import OutStorageModel, OutStorageItemModel, InStorageModel, InStorageItemModel
from production_info.models import DailyProductTaskModel, DailyProductProcessModel, DailyProductMaterialModel, \
    DailyProductTaskItemModel


class DailyProductTaskItemSerializer(serializers.ModelSerializer):
    """
        每日生产任务项目的序列化
    """

    class Meta:
        model = DailyProductTaskItemModel
        fields = '__all__'


class DailyProductMaterialSerializer(serializers.ModelSerializer):
    """
        每日生产任务：生产物料的序列化器
    """

    # 当前库存
    # read_only=True代表：只是用于序列化，不是反序列化
    cur_inventory = serializers.SerializerMethodField(read_only=True, help_text='在当前仓库中的库存')

    class Meta:
        model = DailyProductMaterialModel
        fields = '__all__'

    def get_cur_inventory(self, obj: DailyProductMaterialModel):
        # 当前obj是：DailyProductMaterialModel对象
        result = get_inventory_by_goods(obj.goods.id)
        # 如果result有就返回result，如果result没有就返回0。
        return result if result else 0


class DailyProductProcessSerializer(serializers.ModelSerializer):
    """
        每日生产任务：生产工序的序列化器
    """

    class Meta:
        model = DailyProductProcessModel
        fields = '__all__'


class DailyProductTaskSerializer(serializers.ModelSerializer):
    """
        每日生产任务的序列化
    """

    # 每日生产任务中：项目列表
    # write_only=True
    daily_product_task_item_list = DailyProductTaskItemSerializer(many=True)

    # 每日生产任务中：生产物料列表
    daily_material_list = DailyProductMaterialSerializer(many=True)

    # 每日生产任务中：生产工序列表
    daily_process_list = DailyProductProcessSerializer(many=True)

    class Meta:

        model = DailyProductTaskModel
        fields = '__all__'

    def create(self, validated_data):
        daily_product_task_item_list = validated_data.pop('daily_product_task_item_list')
        daily_material_list = validated_data.pop('daily_material_list')
        daily_process_list = validated_data.pop('daily_process_list')

        with transaction.atomic():
            dpt = DailyProductTaskModel.objects.create(**validated_data)
            for item in daily_product_task_item_list:
                DailyProductTaskItemModel.objects.create(daily_product_task=dpt, **item)
            for item in daily_material_list:
                DailyProductMaterialModel.objects.create(daily_product_task=dpt, **item)
            for item in daily_process_list:
                DailyProductProcessModel.objects.create(daily_product_task=dpt, **item)
        return dpt

    def update(self, instance, validated_data):

        daily_product_task_item_list = []
        daily_material_list = []
        daily_process_list = []

        # if instance.status == '2':
        #     raise ValidationError("生产任务已完工，不能修改")

        if 'daily_product_task_item_list' in validated_data:
            daily_product_task_item_list = validated_data.pop('daily_product_task_item_list')
        if 'daily_material_list' in validated_data:
            daily_material_list = validated_data.pop('daily_material_list')
        if 'daily_process_list' in validated_data:
            daily_process_list = validated_data.pop('daily_process_list')

        old_item_list = instance.daily_product_task_item_list
        old_material_list = instance.daily_material_list
        old_process_list = instance.daily_process_list

        with transaction.atomic():
            if daily_product_task_item_list and old_item_list.exists():
                instance.daily_product_task_item_list.all().delete()
            if daily_material_list and old_material_list.exists():
                instance.daily_material_list.all().delete()
            if daily_process_list and old_process_list.exists():
                instance.daily_process_list.all().delete()

            for item in daily_product_task_item_list:
                DailyProductTaskItemModel.objects.create(daily_product_task=instance, **item)
            for item in daily_material_list:
                DailyProductMaterialModel.objects.create(daily_product_task=instance, **item)
            for item in daily_process_list:
                DailyProductProcessModel.objects.create(daily_product_task=instance, **item)
            result = super(DailyProductTaskSerializer, self).update(instance=instance, validated_data=validated_data)
        return result


# 解读：
# 1.表单中提交的参数，如果只是来源于某一个固定的Model，可以引用serializers.ModelSerializer，同时要有“class Meta:”
# 2.但是，此处，表单中提交的参数，不仅仅只是来源于同一个Model，所以要引用serializers.Serializer
# 3.因为此处会关联多个Model，引用不同，也不需要”class Meta:“了
class DailyProductGetMaterialsSerializer(serializers.Serializer):
    """
        车间每日生产任务单领料的序列化器
    """

    def create(self, validated_data):
        # 需要完成4件事情
        with transaction.atomic():
            # 1.插入出库单（生产领料单）
            # NumberPrefix['prod_out']：以“prod_out”为前缀
            product_out_storage = OutStorageModel.objects.create(invoices_date=timezone.now(),
                                                                 number_code=generate_code(
                                                                     NumberPrefix['prod_out'].value),
                                                                 last_amount=validated_data['money'],
                                                                 number_count=validated_data['get_count'],
                                                                 daily_product_task_id=validated_data[
                                                                     'daily_product_task_id'], status='1',
                                                                 outbound_category='2')
            # 2.插入出库项目（生产领料项目）
            goods = GoodsModel.objects.get(pk=validated_data['goods_id'])
            wh = WarehouseModel.objects.get(pk=validated_data['warehouse_id'])
            psi = OutStorageItemModel()
            psi.goods_id = goods.id
            psi.specification = goods.specification
            psi.model_number = goods.model_number
            psi.goods_code = goods.goods_code
            psi.goods_category = goods.goods_category
            psi.goods_category_name = goods.goods_category_name
            psi.units = goods.units
            psi.units_name = goods.units.basic_name
            psi.name = goods.name

            psi.out_count = validated_data['get_count']
            psi.out_price = validated_data['price']
            psi.out_money = validated_data['money']
            psi.warehouse_name = wh.name
            psi.warehouse_id = wh.id

            psi.out_storage_id = product_out_storage.id
            psi.save()

            # 3.修改库存数量（更新实时库存）
            GoodsInventoryModel.objects.filter(goods_id=goods.id, warehouse_id=wh.id).update(
                cur_inventory=F('cur_inventory') - psi.out_count)

            # 4.修改生产物料的领料数量
            DailyProductMaterialModel.objects.filter(id=validated_data['material_id']).update(
                get_count=F('get_count') + psi.out_count)

            return product_out_storage

    def update(self, instance, validated_data):
        pass

    goods_number_code = serializers.CharField(help_text='物料的编号或者条码', required=False)
    warehouse_name = serializers.CharField(help_text='领取仓库的名字')
    warehouse_id = serializers.IntegerField(help_text='领取仓库的主键')
    goods_id = serializers.IntegerField(help_text='领取货品的主键')

    get_count = serializers.DecimalField(help_text='领取数量，最多精确到小数点后四位', max_digits=10, decimal_places=4, default=0)
    price = serializers.DecimalField(help_text='领取的成本单价，最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
    money = serializers.DecimalField(help_text='领取的成本总价，最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)

    material_id = serializers.IntegerField(help_text='所属生产物料的主键')
    daily_product_task_id = serializers.IntegerField(help_text='所属生产任务单的主键')



# 解读：
# 1.表单中提交的参数，如果只是来源于某一个固定的Model，可以引用serializers.ModelSerializer，同时要有“class Meta:”
# 2.但是，此处，表单中提交的参数，不仅仅只是来源于同一个Model，所以要引用serializers.Serializer
# 3.因为此处会关联多个Model，引用不同，也不需要”class Meta:“了
class DailyProductBackMaterialsSerializer(serializers.Serializer):
    """
        车间每日生产任务单退料的序列化器
    """

    def create(self, validated_data):
        # 需要完成4件事情
        with transaction.atomic():
            # 1.插入入库单（生产退料单）
            # NumberPrefix['prod_in']：以“prod_in”为前缀
            product_in_storage = InStorageModel.objects.create(invoices_date=timezone.now(),
                                                               number_code=generate_code(
                                                                     NumberPrefix['prod_in'].value),
                                                               last_amount=validated_data['money'],
                                                               number_count=validated_data['back_count'],
                                                               daily_product_task_id=validated_data[
                                                                     'daily_product_task_id'], status='1',
                                                               incoming_category='7')

            # 2.插入入库项目（生产退料项目）
            goods = GoodsModel.objects.get(pk=validated_data['goods_id'])
            wh = WarehouseModel.objects.get(pk=validated_data['warehouse_id'])
            psi = InStorageItemModel()            # 如果是多个物料一块退库，需要加个for循环。
            psi.goods_id = goods.id
            psi.specification = goods.specification
            psi.model_number = goods.model_number
            psi.goods_code = goods.goods_code
            psi.goods_category = goods.goods_category
            psi.goods_category_name = goods.goods_category_name
            psi.units = goods.units
            psi.units_name = goods.units.basic_name
            psi.name = goods.name

            psi.into_count = validated_data['back_count']
            psi.into_price = validated_data['price']
            psi.into_money = validated_data['money']
            psi.warehouse_name = wh.name
            psi.warehouse_id = wh.id

            psi.in_storage_id = product_in_storage.id
            psi.save()

            # 3.修改库存数量（更新实时库存）
            GoodsInventoryModel.objects.filter(goods_id=goods.id, warehouse_id=wh.id).update(
                cur_inventory=F('cur_inventory') + psi.into_count)

            # 4.修改生产物料的退料数量
            DailyProductMaterialModel.objects.filter(id=validated_data['material_id']).update(
                back_count=F('back_count') + psi.into_count)

            return product_in_storage

    def update(self, instance, validated_data):
        pass

    goods_number_code = serializers.CharField(help_text='物料的编号或者条码', required=False)
    warehouse_name = serializers.CharField(help_text='退料仓库的名字')
    warehouse_id = serializers.IntegerField(help_text='退料仓库的主键')
    goods_id = serializers.IntegerField(help_text='退料货品的主键')

    back_count = serializers.DecimalField(help_text='退料数量，最多精确到小数点后四位', max_digits=10, decimal_places=4, default=0)
    price = serializers.DecimalField(help_text='退料的成本单价，最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)
    money = serializers.DecimalField(help_text='退料的成本总价，最多精确到小数点后两位', max_digits=10, decimal_places=2, default=0)

    material_id = serializers.IntegerField(help_text='所属生产物料的主键')
    daily_product_task_id = serializers.IntegerField(help_text='所属生产任务单的主键')

